﻿namespace LyricAccess
{
    using FourWindsBar.WebServicesAccess;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Text.RegularExpressions;
    using System.Web;


    /// <summary>
    /// Class to provide a wrapper to the RESTFul calls to lyrDB
    /// </summary>
    public class LyricsDB : GenericLyricAccess, ILyricAccess
    {
        #region private fields
        /// <summary>
        /// Main web part of searching RESTcall
        /// </summary>
        private string searchCall;

        /// <summary>
        /// Main web part of get lyricsREST call
        /// </summary>
        private string getLyricsCall;

        /// <summary>
        /// Name of app to be sent to lyrDB
        /// </summary>
        private string appName;

        /// <summary>
        /// Error code returned by failed RESTcall
        /// </summary>
        private string errorRESTcall;
        #endregion

        #region constructors
        /// <summary>
        /// Initializes a new instance of the LyricsDB class. Constructor taking the app name from the executable
        /// </summary>
        public LyricsDB()
        {
            this.appName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
            this.SetInstanceStrings();
        }

        /// <summary>
        ///  Initializes a new instance of the LyricsDB class. Constructor taking the app name from parameter
        /// </summary>
        /// <param name="appName">sets appName for class object used in REST calls</param>
        public LyricsDB(string appName)
        {
            this.appName = appName;
            this.SetInstanceStrings();
        }

        #endregion

        #region public metods

        /// <summary>
        /// Gets the name of the song list by track.
        /// </summary>
        /// <param name="song">The name of the song.</param>
        /// <param name="output">The output from lyrDB.</param>
        /// <returns>>boolean value indicating success</returns>
        public bool GetSongListByTrackName(string song, out string output)
        {
            string myRESTcall;

            output = string.Empty;

            // Get the song list first
            myRESTcall = string.Format(this.searchCall, HttpUtility.HtmlEncode(song), "trackname", this.appName);
            if (processRESTresult(myRESTcall, out output))
            { // return the list of matching song titles
                return true;
            }

            return false;
        } // end getSongListBYTrackName#region public methods

        /// <summary>
        /// Get lyrics for the first match of a trackname by an artist from the database.
        /// </summary>
        /// <param name="artist">The name of the artist.</param>
        /// <param name="song">The name of the song.</param>
        /// <param name="output">The output of a successful call.</param>
        /// <returns>boolean value indicating success</returns>
        public bool GetLyrics(string artist, string song, out string output)
        {
            string result;
            output = string.Empty;

            if (this.GetSongListByTrackName(song, out result))
            {
                // Now we have a list of possible tracks based on song name split up into array.
                string[] tracks = Regex.Split(result, "\n");

                // Search through the tracks for the first matching artist and we fetch the lyrics for that one.
                // In short a fairly ignorant approach
                foreach (string track in tracks)
                {
                    string[] values = track.Split('\\');
                    if (values[2] == artist)
                    { // Now we have the matching artist we make the call to get the lyrics.
                        if (this.GetLyricsBySpecificRecordNo(values[0], out result))
                        {
                            output = result;
                            return true;
                        }
                    } // end if on artist name match
                } // end foreach track in tracks
                // We've gone through a bunch of tracks and found no match so...
                return false;
            }
            else
            {   // We got no track list
                return false;
            }
        } // end getLyrics

        /// <summary>
        /// Get the lyrics for a specific song record number in the data base.
        /// </summary>
        /// <param name="number">The number.</param>
        /// <param name="output">The output.</param>
        /// <returns>>boolean value indicating success or failure</returns>
        public bool GetLyricsBySpecificRecordNo(string number, out string output)
        {
            string RESTcall;
            output = string.Empty;

            // Create the REST call
            RESTcall = this.getLyricsCall + number;
            // Make the REST call
            if (processRESTresult(RESTcall, out output))
            { // return the lyrics
                return true;
            }

            return false;
        } // end getLyricsBySpecificRecordNo

        /// <summary>
        /// Gets the name of the song list by artist.
        /// </summary>
        /// <param name="artist">The artist.</param>
        /// <param name="output">A dictionary of track no / name if successful.</param>
        /// <returns>>boolean value indicating success</returns>
        public bool GetSongListByArtistName(string artist, out Dictionary<string, string> output)
        {
            string myRESTcall;
            string RESToutput;

            try
             {
                 // Get the song list first
                 myRESTcall = string.Format(this.searchCall, HttpUtility.HtmlEncode(artist), "artist", this.appName);

                 // Try to fetch artist song list
                 if (processRESTresult(myRESTcall, out RESToutput))
                     {  // return the list of matching song titles

                         // Split single string into array
                         string[] SongList = Regex.Split(RESToutput,"\n");
                
                        // Place name and track number into dictionary, track name is the key because 
                        //it's the number we want when looking up lyrics
                        output = new Dictionary<string,string>();
                        foreach (string SongRef in SongList)
                            {
                              string[] SongValues = SongRef.Split('\\');
                              output.Add(SongValues[0], SongValues[1]);
                            }
                        return true;
                     }
                 else
                     {
                        // Failed so flag so and error code is in output
                        output = null;
                        return false;
                     }
            }
            catch(Exception ex)
            {
                Console.Write ("Error in getsonglistbyartist do something:" + ex.Message);
                output = null;
                return false;
            }
        } // end get SongListByArtistName

        /// <summary>
        /// Gets the song list by in lyrics.
        /// </summary>
        /// <param name="lyricScrap">The lyric scrap.</param>
        /// <param name="output">The output.</param>
        /// <returns>>boolean value indicating success</returns>
        public bool GetSongListByInLyrics(string lyricScrap, out string output)
        {
            output = string.Empty;
            return false;

            // throw new System.NotImplementedException();
        } // end getSongListByIntLyrics

        #endregion

        #region private methods

        /// <summary>
        /// Set the REST call strings, errorRESTcall search string, etc.
        /// </summary>
        private void SetInstanceStrings()
        {
            this.errorRESTcall = "error:";
            this.searchCall = "http://webservices.lyrdb.com/lookup.php?q={0}&for={1}&agent={2}";
            this.getLyricsCall = "http://webservices.lyrdb.com/getlyr.php?q=";
        } // end setInstanceStrings


        /// <summary>
        /// Processes the REST call tresult.
        /// </summary>
        /// <param name="RESTcall">The REST service call.</param>
        /// <param name="result">The result of the serivce call.</param>
        /// <returns>A boolean value indicating if the call was a success</returns>
        private bool processRESTresult(string RESTcall, out string result)
        {

            RESTServices.MakeRESTcall(RESTcall, out result);
            // return error code if failed else return result
            return (((result != string.Empty) && (result.Contains(errorRESTcall))) ? false : true);
        }


        #endregion
    }
}